//  Copyright 2011 Charlie Garrett
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
//  TermVisitor.cpp
//

#include "TermVisitor.h"
#include "CodeGenerator.h"

namespace logic {
    using namespace std;
    
    // TermVisitors
    void TermVisitor::AddTerm(Term *term) {
        switch (order) {
            case DFS_PREORDER:
            case DFS_POSTORDER:
                worklist.push_front(term);
                break;
            case BFS:
                worklist.push_back(term);
                break;
        }
    }
    
    void TermVisitor::Run(Term *initial) {
        switch (order) {
            case DFS_PREORDER:
            case BFS:
                AddTerm(initial);
                while (!worklist.empty()) {
                    Term *term = worklist.front();
                    worklist.pop_front();
                    if (!unique || visited.find(term) == visited.end()) {
                        term->Accept(this);
                        term->AddChildren(this, (order == DFS_PREORDER));
                        visited.insert(term);
                    }
                }
                break;
            case DFS_POSTORDER:
                // Use a recursive approach for this one, calling
                // Run on each term before calling Accept on it.
                initial->AddChildren(this);
                while (!worklist.empty()) {
                    Term *term = worklist.front();
                    worklist.pop_front();
                    Run(term);
                }
                if (!unique || visited.find(initial) == visited.end()) {
                    initial->Accept(this);
                    visited.insert(initial);
                }
                break;
        }
    }
}  // namespace logic
